package com.lagou.util;

import com.lagou.bean.MonitorData;
import org.apache.dubbo.common.utils.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MonitorUtil {

    private static ConcurrentHashMap<String, List<MonitorData>> methodCostTimeMap = new ConcurrentHashMap<>();

    static {
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new TimeCountThread(), 1, 5, TimeUnit.SECONDS);
    }

    //将每次方法调用的时间统计信息添加到集合map中
    public static void addMethodCostTime(long startTime, long costTime, String methodName) {
        MonitorData monitorData = new MonitorData(startTime, costTime);

        List<MonitorData> monitorDataList = methodCostTimeMap.get(methodName);
        if (CollectionUtils.isEmpty(monitorDataList)) {
            monitorDataList = new ArrayList<>();
            methodCostTimeMap.put(methodName, monitorDataList);
        }

        monitorDataList.add(monitorData);
    }


    static class TimeCountThread implements Runnable {
        @Override
        public void run() {

            //将集合中1分钟以前的调用数据清除掉
            long currentTime = System.currentTimeMillis();
            for (String methodName : methodCostTimeMap.keySet()) {
                List<MonitorData> monitorDataList = methodCostTimeMap.get(methodName);
                if (CollectionUtils.isEmpty(monitorDataList)) {
                    continue;
                }
                //因为数据是按照时间先后顺序添加的，如果数组里的第一条时间超过一分钟，说明需要清除数据
                if (currentTime - monitorDataList.get(0).getStartTime() > 60000) {

                    //如果数组中最后一个数据也过期，清空数组
                    if (currentTime - monitorDataList.get(monitorDataList.size() - 1).getStartTime() > 60000) {
                        monitorDataList = new ArrayList<>();
                        methodCostTimeMap.put(methodName, monitorDataList);
                    }

                    for (int i = 0; i < monitorDataList.size(); i++) {
                        //找到一分钟的临界数组索引
                        if (currentTime - monitorDataList.get(i).getStartTime() < 60000) {
                            monitorDataList = monitorDataList.subList(i, monitorDataList.size());
                            methodCostTimeMap.put(methodName, monitorDataList);
                            break;
                        }
                    }
                }

            }

            //开始统计每个方法对应的TP90，TP99数据
            for (String methodName : methodCostTimeMap.keySet()) {
                List<MonitorData> monitorDataList = methodCostTimeMap.get(methodName);
                if (CollectionUtils.isEmpty(monitorDataList)) {
                    continue;
                }

                List<Long> methodCostTimeList = new ArrayList<>(monitorDataList.size());
                for (MonitorData monitorData : monitorDataList) {
                    long costTime = monitorData.getCostTime();

                    methodCostTimeList.add(costTime);
                }

                //将数据按照调用时间从小到大排序
                Collections.sort(methodCostTimeList);

                //计算TP90对应的index
                int tp90Index = (int) Math.floor(methodCostTimeList.size() * 0.9);
                //计算TP99对应的index
                int tp99Index = (int) Math.floor(methodCostTimeList.size() * 0.99);


                System.out.println(methodName + "一分钟内的调用耗时列表=" + methodCostTimeList);

                System.out.println(methodName + " 的TP90=" + methodCostTimeList.get(tp90Index) + "，TP99=" + methodCostTimeList.get(tp99Index));
            }
        }
    }
}
